home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Environments
/
PowerMacOberon feb96
/
Source
/
ClipFrames.Mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1994-07-11
|
13KB
|
297 lines
Syntax10.Scn.Fnt
MODULE ClipFrames; (* J. Templ, 30.10.90/28.6.91 *)
(* ClipFrames.Frame provides basic drawing operations clipped on the frame borders.
all drawing and mouse coordinates are relative to the origin x0, y0, which is relative to the
top left corner of the frame. Capital letter coordinates always denote screen coordinates.
In addition, ClipFrames contains two other useful frame classes, one for printing, and one
for finding the bounding box*)
IMPORT
Oberon, Input, Display, Display1, Fonts, MenuViewers, TextFrames, GraphicOps, Texts, Printer;
TYPE
Frame* = POINTER TO FrameDesc;
FrameDesc* = RECORD (Display.FrameDesc)
col*, x0*, y0*, scale*: INTEGER;
ext*: Frame;
END ;
PrintFrame* = POINTER TO PrintFrameDesc;
PrintFrameDesc* = RECORD
(FrameDesc)
END ;
BalloonFrame* = POINTER TO BalloonFrameDesc; (* inspired by B. Stamm *)
BalloonFrameDesc* = RECORD
(FrameDesc)
END ;
Lclip, Rclip, Bclip, Tclip: INTEGER; (* current clipping rectangle *)
PROCEDURE Clip(F: Frame);
BEGIN
Lclip := F.X; Rclip := F.X + F.W; Bclip := F.Y; Tclip := F.Y + F.H
END Clip;
PROCEDURE Intersect(F: Frame; VAR X, Y, W, H: INTEGER): BOOLEAN;
VAR t: INTEGER;
BEGIN
t := X + W;
IF F.X > X THEN X := F.X END;
IF F.X + F.W < t THEN W := F.X + F.W - X ELSE W := t - X END;
IF W <= 0 THEN RETURN FALSE END;
t := Y + H;
IF F.Y > Y THEN Y := F.Y END;
IF F.Y + F.H < t THEN H := F.Y + F.H - Y ELSE H := t - Y END;
RETURN H > 0
END Intersect;
PROCEDURE MinMax(x, y: INTEGER; VAR min, max: INTEGER);
BEGIN IF x < y THEN min := x; max := y ELSE min := y; max := x END
END MinMax;
PROCEDURE Update (F: Frame; x, y, w, h: INTEGER);
BEGIN x := x + F.x0; y := y + F.y0;
IF x < F.X THEN F.W := F.W + F.X - x; F.X := x END ;
IF x + w > F.X + F.W THEN F.W := x + w - F.X END ;
IF y < F.Y THEN F.H := F.H + F.Y - y; F.Y := y END ;
IF y + h > F.Y + F.H THEN F.H := y + h - F.Y END
END Update;
(* ----------------- coordinate conversion methods ------------------ *)
PROCEDURE (F: Frame) CX*(x: INTEGER): INTEGER;
BEGIN RETURN F.X + (F.x0 + x) DIV F.scale
END CX;
PROCEDURE (F: Frame) CY*(y: INTEGER): INTEGER;
BEGIN RETURN F.Y + F.H + (F.y0 + y) DIV F.scale
END CY;
PROCEDURE (F: Frame) Cx*(X: INTEGER): INTEGER;
BEGIN RETURN (X - F.X) * F.scale - F.x0
END Cx;
PROCEDURE (F: Frame) Cy*(Y: INTEGER): INTEGER;
BEGIN RETURN (Y - F.Y - F.H) * F.scale - F.y0
END Cy;
(* ----------------- screen drawing methods ------------------ *)
PROCEDURE (F: Frame) DrawLine*(x1, y1, x2, y2, col, mode: INTEGER);
BEGIN
GraphicOps.Line(F, F.CX(x1), F.CY(y1), F.CX(x2), F.CY(y2), 1, Display1.ThisPattern(col), col)
END DrawLine;
PROCEDURE (F: Frame) DrawRect*(x, y, w, h, col, mode: INTEGER);
BEGIN
F.DrawLine(x, y, x+w, y, col, mode);
F.DrawLine(x+w, y, x+w, y+h, col, mode);
F.DrawLine(x, y+h, x+w, y+h, col, mode);
F.DrawLine(x, y, x, y+h, col, mode);
IF F.scale = 1 THEN
F.DrawLine(x, y+1, x+w, y+1, col, mode);
F.DrawLine(x, y+2, x+w, y+2, col, mode);
F.DrawLine(x+w-1, y, x+w-1, y+h, col, mode);
F.DrawLine(x+w-2, y, x+w-2, y+h, col, mode);
F.DrawLine(x, y+h-1, x+w, y+h-1, col, mode);
F.DrawLine(x, y+h-2, x+w, y+h-2, col, mode);
F.DrawLine(x+1, y, x+1, y+h, col, mode);
F.DrawLine(x+2, y, x+2, y+h, col, mode);
END
END DrawRect;
PROCEDURE ClippedDot4(x1, x2, y1, y2, col, mode: INTEGER);
BEGIN
IF (Lclip <= x1) & (x1 < Rclip) THEN
IF (Bclip <= y1) & (y1 < Tclip) THEN Display.ReplConst(col, x1, y1, 1, 1, mode) END;
IF (Bclip <= y2) & (y2 < Tclip) THEN Display.ReplConst(col, x1, y2, 1, 1, mode) END
END;
IF (Lclip <= x2) & (x2 < Rclip) THEN
IF (Bclip <= y1) & (y1 < Tclip) THEN Display.ReplConst(col, x2, y1, 1, 1, mode) END;
IF (Bclip <= y2) & (y2 < Tclip) THEN Display.ReplConst(col, x2, y2, 1, 1, mode) END
END
END ClippedDot4;
PROCEDURE (F: Frame) DrawCircle*(x, y, r, col, mode: INTEGER);
VAR x1, y1, d, dx, dy: INTEGER;
BEGIN
Clip(F);
x := F.CX(x); y := F.CY(y); r := r DIV F.scale;
x1 := r; y1 := 0; dx := 8*(x1-1); dy := 8*y1+4; d := 1-4*r;
WHILE x1 > y1 DO
ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
ClippedDot4(x-y1-1, x+y1, y-x1-1, y+x1, col, mode);
INC(d, dy); INC(dy, 8); INC(y1);
IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x1) END
END;
IF x1 = y1 THEN ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode) END
END DrawCircle;
PROCEDURE (F: Frame) DrawEllipse*(x, y, a, b, col, mode: INTEGER);
VAR
x1, y1: INTEGER;
d, dx, dy, x2, y2, a1, a2, a8, b1, b2, b8: LONGINT;
BEGIN
Clip(F);
x := F.CX(x); y := F.CY(y);
IF (Lclip<=x+a) OR (x-a<=Rclip) OR (Bclip<=y+b) OR (y-b<=Tclip) THEN (* ellipse may be visible *)
a1 := a; a2 := a1*a1; a8 := 8*a2; b1 := b; b2 := b1*b1; b8 := 8*b2;
x1 := a; y1 := 0; x2 := a1*b2; y2 := 0; dx := b8*(a1-1); dy := 4*a2; d := b2*(1- 4*a1);
WHILE y2 < x2 DO
ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
INC(d, dy); INC(dy, a8); INC(y1); INC(y2, a2);
IF d >= 0 THEN DEC(d, dx); DEC(dx, b8); DEC(x1); DEC(x2, b2) END
END;
INC(d, 4*(x2+y2)-b2+a2);
WHILE x1 >= 0 DO
ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
DEC(d, dx); DEC(dx, b8); DEC(x1);
IF d < 0 THEN INC(d, dy); INC(dy, a8); INC(y1) END
END
END
END DrawEllipse;
PROCEDURE (F: Frame) DrawString*(x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
VAR ch: CHAR; pat: LONGINT; i, dx, chx, chy, chw, chh, chL, chB, chLOld, chBOld, chwOld, chhOld: INTEGER;
BEGIN
x := F.CX(x); y := F.CY(y);
ch := s[0]; i := 0;
WHILE ch # 0X DO
Display.GetChar(font.raster, ch, dx, chx, chy, chw, chh, pat);
chL := x+chx; chB := y+chy;
chLOld := chL; chBOld := chB; chwOld := chw; chhOld := chh;
IF Intersect(F, chL, chB, chw, chh) THEN
IF (chw = chwOld) & (chh = chhOld) THEN
Display.CopyPattern(col, pat, chL, chB, mode);
ELSE
Display.CopyBlock(chL, chB, chw, chh, chL-chLOld, -chhOld+chB-chBOld, Display.replace);
Display.CopyPattern(col, pat, 0, -chhOld, mode);
Display.CopyBlock(chL-chLOld, -chhOld+chB-chBOld, chw, chh, chL, chB, Display.replace)
END
END ;
INC(x, dx * 4 DIV F.scale); INC(i); ch := s[i]
END
END DrawString;
PROCEDURE (F: Frame) FillRect* (x, y, w, h, col, mode: INTEGER);
BEGIN
x := F.CX(x); y := F.CY(y); w := w DIV F.scale; h := h DIV F.scale;
IF Intersect(F, x, y, w, h) THEN Display.ReplPattern(col, Display1.ThisPattern(col), x, y, w, h, mode) END
END FillRect;
PROCEDURE (F: Frame) FillCircle* (x, y, r, col, mode: INTEGER);
BEGIN
GraphicOps.Ellipse(F, F.CX(x), F.CY(y), r, r, 1, Display1.ThisPattern(col), col)
END FillCircle;
PROCEDURE (F: Frame) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, mode: INTEGER); (* by B. Stamm *)
TYPE LineParms = RECORD x,y,d,dx,dy,inx,iny,drawX,drawY: INTEGER END;
VAR x,y,RHS2,RHS3: INTEGER; left,right: LineParms;
PROCEDURE InitLineParms(x1,y1,x2,y2: INTEGER; VAR p: LineParms);
BEGIN
p.x := x1; p.dx := x2-x1; IF p.dx > 0 THEN p.inx := 1 ELSIF p.dx < 0 THEN p.inx := -1; p.dx := -p.dx ELSE p.inx := 0 END;
p.y := y1; p.dy := y2-y1; IF p.dy > 0 THEN p.iny := 1 ELSIF p.dy < 0 THEN p.iny := -1; p.dy := -p.dy ELSE p.iny := 0 END;
p.d := p.dy - p.dx; p.dx := 2*p.dx; p.dy := 2*p.dy;
END InitLineParms;
PROCEDURE LineStep(VAR p: LineParms);
(* H = (d(x,y) := (2*x - 2*x1 + 1)*dy - (2*y - 2*y1 + 1)*dx < 0) *)
BEGIN
WHILE p.d < 0 DO INC(p.x,p.inx); INC(p.d,p.dy) END;
p.drawX := p.x; p.drawY := p.iny DIV 2 + p.y;
DEC(p.d,p.dx); INC(p.y,p.iny);
END LineStep;
BEGIN (* Quadrangle *)
x1 := F.CX(x1); x2 := F.CX(x2); x3 := F.CX(x3); x4 := F.CX(x4);
y1 := F.CY(y1); y2 := F.CY(y2); y3 := F.CY(y3); y4 := F.CY(y4);
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
IF (y3>y4) OR (y3=y4) & (x3>x4) THEN x := x3; x3 := x4; x4 := x; y := y3; y3 := y4; y4 := y END;
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF LONG(x2-x1)*LONG(y4-y1) > LONG(y2-y1)*LONG(x4-x1) THEN RHS2 := 2 ELSE RHS2 := 0 END;
IF LONG(x3-x1)*LONG(y4-y1) > LONG(y3-y1)*LONG(x4-x1) THEN RHS3 := 1 ELSE RHS3 := 0 END;
CASE RHS2 + RHS3 OF
| 0: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x4,y4,right);
| 1: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x3,y3,right);
| 2: InitLineParms(x1,y1,x3,y3,left); InitLineParms(x1,y1,x2,y2,right);
| 3: InitLineParms(x1,y1,x4,y4,left); InitLineParms(x1,y1,x2,y2,right);
END;
WHILE left.y # y2 DO
LineStep(left); LineStep(right);
F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
END;
CASE RHS2 + RHS3 OF
| 0: InitLineParms(x2,y2,x3,y3,left);
| 1: InitLineParms(x2,y2,x4,y4,left);
| 2: InitLineParms(x2,y2,x4,y4,right);
| 3: InitLineParms(x2,y2,x3,y3,right);
END;
WHILE left.y # y3 DO
LineStep(left); LineStep(right);
F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
END;
CASE RHS2 + RHS3 OF
| 0,2: InitLineParms(x3,y3,x4,y4,left);
| 1,3: InitLineParms(x3,y3,x4,y4,right);
END;
WHILE left.y # y4 DO
LineStep(left); LineStep(right);
F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
END
END FillQuad;
(* ----------------- printer drawing methods ------------------ *)
PROCEDURE (F: PrintFrame) DrawRect* (x, y, w, h, col, mode: INTEGER);
BEGIN
x := F.CX(x)-1; y := F.CY(y)-1;
Printer.ReplConst(x, y, w, 3);
Printer.ReplConst(x+w, y, 3, h+3);
Printer.ReplConst(x, y+h, w, 3);
Printer.ReplConst(x, y, 3, h);
END DrawRect;
PROCEDURE (F: PrintFrame) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
BEGIN
x1 := F.CX(x1); y1 := F.CY(y1);
x2 := F.CX(x2); y2 := F.CY(y2);
Printer.Line(x1, y1, x2, y2)
END DrawLine;
PROCEDURE (F: PrintFrame) DrawCircle* (x, y, r, col, mode: INTEGER);
BEGIN Printer.Circle(F.CX(x), F.CY(y), r)
END DrawCircle;
PROCEDURE (F: PrintFrame) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
BEGIN Printer.Ellipse(F.CX(x), F.CY(y), a, b)
END DrawEllipse;
PROCEDURE (F: PrintFrame) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
BEGIN
Printer.String(F.CX(x), F.CY(y), s, font.name)
END DrawString;
PROCEDURE (F: PrintFrame) FillRect* (x, y, w, h, col, mode: INTEGER);
BEGIN Printer.ReplPattern(F.CX(x), F.CY(y), w, h, col);
END FillRect;
PROCEDURE (F: PrintFrame) FillCircle* (x, y, r, col, mode: INTEGER);
VAR error: ARRAY 32 OF CHAR;
BEGIN error := "not yet implemented";
HALT(99)
END FillCircle;
(* ----------------- methods for finding the bounding box------------------ *)
PROCEDURE (F: BalloonFrame) DrawRect* (x, y, w, h, col, mode: INTEGER);
BEGIN Update(F, x, y, w, h)
END DrawRect;
PROCEDURE (F: BalloonFrame) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
VAR minx, miny, maxx, maxy: INTEGER;
BEGIN
MinMax(x1, x2, minx, maxx);
MinMax(y1, y2, miny, maxy);
Update(F, minx, miny, maxx - minx, maxy - miny)
END DrawLine;
PROCEDURE (F: BalloonFrame) DrawCircle* (x, y, r, col, mode: INTEGER);
BEGIN Update(F, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
END DrawCircle;
PROCEDURE (F: BalloonFrame) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
BEGIN Update(F, x - a - 4, y - b - 4, 2 * a + 4, 2 * b + 4)
END DrawEllipse;
PROCEDURE (F: BalloonFrame) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
VAR i, w, dx, X, Y, W, H: INTEGER; p: LONGINT; ch: CHAR;
BEGIN
i := 0; w := 0; ch := s[0];
WHILE ch # 0X DO Display.GetChar(font.raster, ch, dx, X, Y, W, H, p); INC(w, dx * 4); INC(i); ch := s[i] END ;
Update(F, x, y, w, font.height*4)
END DrawString;
PROCEDURE (F: BalloonFrame) FillRect* (x, y, w, h, col, mode: INTEGER);
BEGIN Update(F, x, y, w, h)
END FillRect;
PROCEDURE (F: BalloonFrame) FillCircle* (x, y, r, col, mode: INTEGER);
BEGIN Update(F, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
END FillCircle;
PROCEDURE (F: BalloonFrame) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, mode: INTEGER);
BEGIN
MinMax(x1, x2, x1, x2); MinMax(x2, x3, x2, x3); MinMax(x3, x4, x3, x4);
MinMax(x2, x3, x2, x3); MinMax(x1, x2, x1, x2);
MinMax(y1, y2, y1, y2); MinMax(y2, y3, y2, y3); MinMax(y3, y4, y3, y4);
MinMax(y2, y3, y2, y3); MinMax(y1, y2, y1, y2);
Update(F, x1, y1, x4 - x1, y4 - y1)
END FillQuad;
PROCEDURE InitBalloon*(F: BalloonFrame);
BEGIN F.scale := 1;
F.X := 10000; F.Y := 10000;
F.W := -20000; F.H := -20000
END InitBalloon;
END ClipFrames.